package org.springblade.dev;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.IFill;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Property;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

import java.util.Collections;
import java.util.List;
import java.util.Properties;

/**
 * 保留版权 : CopyRright (c) Armyant
 * 文件名称 : CodeGenerator.java
 * 文件编号 : 1-1-1
 * 功能描述 :
 * 文件版本 : 2024.01.17.01
 * 创建人名 : 于继业
 * 创建日期 : 2024-01-17
 * 修改人名 :
 * 修改日期 :
 *
 * @author 于继业
 */
@Slf4j
public class TestCodeGenerator {
    public static void main(String[] args) throws InterruptedException {
        // 模块名，必填
        String moduleName = "user";

        // 需要生成的表名，必填
        List<String> tables = ListUtil.toList("fenrun_assist");

        // 去除表前缀，非必填
        String offSetTablePrefix = "t_";

        // 属性值填充策略，非必填
        List<IFill> tableFillList = ListUtil.toList(
                new Property("createDate", FieldFill.INSERT),
                new Property("updateDate", FieldFill.INSERT_UPDATE)
        );

        if (StrUtil.isBlank(moduleName) || CollUtil.isEmpty(tables)) {
            log.info("请输入模块名和需要生成的表名!");
            return;
        }


        String projectPath = System.getProperty("user.dir");

        // 全局配置
        GlobalConfig config = new GlobalConfig.Builder()
                // 作者
                .author("armyant")
                // 生成文件输出路径(写到java目录)
                .outputDir(projectPath + "/src/main/java")
                // 开启swagger
                .enableSwagger()
                // 注释日期格式
                .commentDate("yyyy-MM-dd")
                // 覆盖文件(需谨慎使用)
                .fileOverride()
                // 设置时间对应类型
                .dateType(DateType.ONLY_DATE)
                // 生成后不要打开目录
                .disableOpenDir()
                .build();

        // 包名配置
        PackageConfig packageConfig = new PackageConfig.Builder()
                // 父包名
                .parent("org.springblade.modules")
                // 父包模块名
                .moduleName(moduleName)
                // Controller 包名
                .controller("controller")
                // Service 包名
                .service("service")
                // Service Impl 包名
                .serviceImpl("service.impl")
                // Entity 包名
                .entity("entity")
                // Mapper 包名
                .mapper("mapper")
                // Mapper XML 包名
                .xml("mapper")
                // 自定义文件包名
                //.other("")
                // 路径配置信息
                // .pathInfo( Collections.singletonMap(OutputFile.mapperXml, projectPath + "/src/main/resources/mapper/" + moduleName))
                .build();

        // 模板配置(TemplateConfig)
        TemplateConfig templateConfig = new TemplateConfig.Builder()
                // 禁用所有模板
                //.disable()
                // 禁用模板
                // .disable(TemplateType.ENTITY)
                // 设置实体模板路径(JAVA)
                // .entity("/boot/entity.java")
                // 设置实体模板路径(kotlin)
                //.entityKt("")
                // 设置 service 模板路径
                .service("/boot/service.java")
                // 设置 serviceImpl 模板路径
                .serviceImpl("/boot/serviceImpl.java")
                // 设置 mapper 模板路径
                .mapper("/boot/mapper.java")
                // 设置 mapperXml 模板路径
                .xml("/boot/mapper.xml")
                // 设置 controller 模板路径
                .controller("/boot/controller.java")
                .build();


        // 注入配置(InjectionConfig)
        InjectionConfig injectionConfig = new InjectionConfig.Builder()
                // 输出文件之前消费者
                .beforeOutputFile((tableInfo, objectMap) -> log.info("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size()))
                // 自定义配置 Map 对象
                // Collections.singletonMap("test", "baomidou")
                .customMap(Collections.singletonMap("entityVO.java", "baomidou"))
                // 自定义配置模板文件
                // Collections.singletonMap("test.txt", "/templates/test.vm") 方法 formatNameFunction 可以格式化文件，
                // 参考测试用例 H2CodeGeneratorTest.testCustomFileByList
                .customFile(new CustomFile.Builder().fileName("VO.java").templatePath("/boot/entityVO.java.vm").packageName("vo").build())
                .build();

        // 策略配置
        StrategyConfig strategyConfig = new StrategyConfig.Builder()
                .addTablePrefix(offSetTablePrefix)                  // 需要抵消的表前缀
                .addInclude(tables)                                 // 设置生成需要映射的表名
                //.enableCapitalMode()                              //策略开启⼤写命名
                .serviceBuilder()                                   // 构建Service层
                .formatServiceFileName("I%sService")                 // 业务层接口类命名
                .formatServiceImplFileName("%sServiceImpl")         // 业务层接口实现类命名
                .entityBuilder()                                    // 构建实体类
                .columnNaming(NamingStrategy.underline_to_camel)    // 字段名驼峰命名
                .naming(NamingStrategy.underline_to_camel)          // 表名驼峰命名
                // 设置文件名
                // .formatFileName("%sEntity")
                .enableLombok()                                     // 添加lombock的getter、setter注解
                .enableChainModel()                                 // 启动链式写法@Accessors(chain = true)
                .enableColumnConstant()                             // 启动属性转常量功能@FieldNameConstants
                .logicDeleteColumnName("deleted")                   // 逻辑删除字段，标记@TableLogic
                .enableTableFieldAnnotation()                       // 启动字段注解
                .addTableFills(tableFillList)                       // 属性值填充策略
                .controllerBuilder()                                // 构建Controller类
                .enableHyphenStyle()                                // 映射路径使用连字符格式，而不是驼峰
                .formatFileName("%sController")                     // Controller类命名
                //.superClass(BaseController.class)                   //Controller 类继承 BaseController
                .enableRestStyle()                                  // 标记@RestController注解
                .mapperBuilder()                                    // 构建mapper接口类
                .enableBaseResultMap()                              // 生成基本的resultMap
                .formatMapperFileName("%sMapper")                   // Mapper接口类明名
                .superClass(BaseMapper.class)                       // Mapper接口类集成 BaseMapper
                .enableMapperAnnotation()                           // 标记@Mapper注解
                .formatXmlFileName("%sMapper")                      // Mapper.xml命名
                .enableBaseColumnList()                             // 生成基本的SQL片段
                .build();

        // 数据源配置
        DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig
                .Builder(
                "jdbc:mysql://mysql.yl-mall.cn:63463/yl_htyk?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true",
                "root", "Mysql!2$");

        // 类型转换
        dataSourceConfigBuilder.typeConvert(new MySqlTypeConvert() {
            @Override
            public IColumnType processTypeConvert(GlobalConfig globalConfig, String tableField) {
                if (tableField.toLowerCase().contains("date") || tableField.toLowerCase().contains("timestamp") || tableField.toLowerCase().contains("datetime")) {
                    return DbColumnType.DATE;
                }
                return super.processTypeConvert(globalConfig, tableField);
            }
        });

        // 创建代码生成器对象，加载配置
        AutoGenerator autoGenerator = new AutoGenerator(dataSourceConfigBuilder.build());
        autoGenerator.global(config);
        autoGenerator.injection(injectionConfig);
        autoGenerator.template(templateConfig);
        autoGenerator.packageInfo(packageConfig);
        autoGenerator.strategy(strategyConfig);

        // 执行
        autoGenerator.execute();
        System.out.println("========================================  Done 相关代码生成完毕  =====================================");
    }

    /**
     * 获取配置文件
     *
     * @return 配置Props
     */
    @SneakyThrows
    private Properties getProperties() {
        // 读取配置文件
        Resource resource = new ClassPathResource("/code.properties");

        return PropertiesLoaderUtils.loadProperties(resource);
    }
}
